/***********************************************************************/
/*                                                                     */
/*                           Objective Caml                            */
/*                                                                     */
/*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         */
/*                                                                     */
/*  Copyright 1996 Institut National de Recherche en Informatique et   */
/*  en Automatique.  All rights reserved.  This file is distributed    */
/*  under the terms of the GNU Lesser General Public License, with     */
/*  the special exception on linking described in file ../LICENSE.     */
/*                                                                     */
/***********************************************************************/

/* $Id: parsing.c 8983 2008-08-06 09:38:25Z xleroy $ */

/* The PDA automaton for parsers generated by camlyacc */

/* The pushdown automata */

//Provides: caml_parser_trace
var caml_parser_trace = 0;

//Provides: caml_parse_engine
//Requires: caml_lex_array, caml_parser_trace,caml_jsstring_of_string
//Requires: caml_ml_output, caml_ml_string_length, caml_string_of_jsbytes
//Requires: caml_jsbytes_of_string, MlBytes
//Requires: caml_sys_fds
function caml_parse_engine(tables, env, cmd, arg) {
  var ERRCODE = 256;

  //var START = 0;
  //var TOKEN_READ = 1;
  //var STACKS_GROWN_1 = 2;
  //var STACKS_GROWN_2 = 3;
  //var SEMANTIC_ACTION_COMPUTED = 4;
  //var ERROR_DETECTED = 5;
  var loop = 6;
  var testshift = 7;
  var shift = 8;
  var shift_recover = 9;
  var reduce = 10;

  var READ_TOKEN = 0;
  var RAISE_PARSE_ERROR = 1;
  var GROW_STACKS_1 = 2;
  var GROW_STACKS_2 = 3;
  var COMPUTE_SEMANTIC_ACTION = 4;
  var CALL_ERROR_FUNCTION = 5;

  var env_s_stack = 1;
  var env_v_stack = 2;
  var env_symb_start_stack = 3;
  var env_symb_end_stack = 4;
  var env_stacksize = 5;
  var env_stackbase = 6;
  var env_curr_char = 7;
  var env_lval = 8;
  var env_symb_start = 9;
  var env_symb_end = 10;
  var env_asp = 11;
  var env_rule_len = 12;
  var env_rule_number = 13;
  var env_sp = 14;
  var env_state = 15;
  var env_errflag = 16;

  // var _tbl_actions = 1;
  var tbl_transl_const = 2;
  var tbl_transl_block = 3;
  var tbl_lhs = 4;
  var tbl_len = 5;
  var tbl_defred = 6;
  var tbl_dgoto = 7;
  var tbl_sindex = 8;
  var tbl_rindex = 9;
  var tbl_gindex = 10;
  var tbl_tablesize = 11;
  var tbl_table = 12;
  var tbl_check = 13;
  // var _tbl_error_function = 14;
  var tbl_names_const = 15;
  var tbl_names_block = 16;

  function log(x) {
    var s = caml_string_of_jsbytes(x + "\n");
    caml_ml_output(caml_sys_fds[2].chanid, s, 0, caml_ml_string_length(s));
  }

  function token_name(names, number) {
    var str = caml_jsstring_of_string(names);
    if (str[0] === "\x00") return "<unknown token>";
    return str.split("\x00")[number];
  }

  function print_token(state, tok) {
    var token, kind;
    if (Array.isArray(tok)) {
      token = token_name(tables[tbl_names_block], tok[0]);
      if (typeof tok[1] === "number") kind = "" + tok[1];
      else if (typeof tok[1] === "string") kind = tok[1];
      else if (tok[1] instanceof MlBytes) kind = caml_jsbytes_of_string(tok[1]);
      else kind = "_";
      log("State " + state + ": read token " + token + "(" + kind + ")");
    } else {
      token = token_name(tables[tbl_names_const], tok);
      log("State " + state + ": read token " + token);
    }
  }

  if (!tables.dgoto) {
    tables.defred = caml_lex_array(tables[tbl_defred]);
    tables.sindex = caml_lex_array(tables[tbl_sindex]);
    tables.check = caml_lex_array(tables[tbl_check]);
    tables.rindex = caml_lex_array(tables[tbl_rindex]);
    tables.table = caml_lex_array(tables[tbl_table]);
    tables.len = caml_lex_array(tables[tbl_len]);
    tables.lhs = caml_lex_array(tables[tbl_lhs]);
    tables.gindex = caml_lex_array(tables[tbl_gindex]);
    tables.dgoto = caml_lex_array(tables[tbl_dgoto]);
  }

  var res = 0,
    n,
    n1,
    n2,
    state1;

  // RESTORE
  var sp = env[env_sp];
  var state = env[env_state];
  var errflag = env[env_errflag];

  the_loop: for (;;) {
    switch (cmd) {
      case 0: //START:
        // biome-ignore lint/suspicious/noFallthroughSwitchClause:
        state = 0;
        errflag = 0;
      // fallthrough

      case 6: //loop:
        n = tables.defred[state];
        if (n !== 0) {
          cmd = reduce;
          continue the_loop;
        }
        if (env[env_curr_char] >= 0) {
          cmd = testshift;
          continue the_loop;
        }
        res = READ_TOKEN;
        break the_loop;
      /* The ML code calls the lexer and updates */
      /* symb_start and symb_end */
      case 1: //TOKEN_READ:
        // biome-ignore lint/suspicious/noFallthroughSwitchClause:
        if (Array.isArray(arg)) {
          env[env_curr_char] = tables[tbl_transl_block][arg[0] + 1];
          env[env_lval] = arg[1];
        } else {
          env[env_curr_char] = tables[tbl_transl_const][arg + 1];
          env[env_lval] = 0;
        }
        if (caml_parser_trace) print_token(state, arg);
      // fallthrough

      case 7: //testshift:
        // biome-ignore lint/suspicious/noFallthroughSwitchClause:
        n1 = tables.sindex[state];
        n2 = n1 + env[env_curr_char];
        if (
          n1 !== 0 &&
          n2 >= 0 &&
          n2 <= tables[tbl_tablesize] &&
          tables.check[n2] === env[env_curr_char]
        ) {
          cmd = shift;
          continue the_loop;
        }
        n1 = tables.rindex[state];
        n2 = n1 + env[env_curr_char];
        if (
          n1 !== 0 &&
          n2 >= 0 &&
          n2 <= tables[tbl_tablesize] &&
          tables.check[n2] === env[env_curr_char]
        ) {
          n = tables.table[n2];
          cmd = reduce;
          continue the_loop;
        }
        if (errflag <= 0) {
          res = CALL_ERROR_FUNCTION;
          break the_loop;
        }
      // fallthrough
      /* The ML code calls the error function */
      case 5: //ERROR_DETECTED:
        if (errflag < 3) {
          errflag = 3;
          for (;;) {
            state1 = env[env_s_stack][sp + 1];
            n1 = tables.sindex[state1];
            n2 = n1 + ERRCODE;
            if (
              n1 !== 0 &&
              n2 >= 0 &&
              n2 <= tables[tbl_tablesize] &&
              tables.check[n2] === ERRCODE
            ) {
              if (caml_parser_trace) log("Recovering in state " + state1);
              cmd = shift_recover;
              continue the_loop;
            } else {
              if (caml_parser_trace) log("Discarding state " + state1);
              if (sp <= env[env_stackbase]) {
                if (caml_parser_trace) log("No more states to discard");
                return RAISE_PARSE_ERROR;
              }
              /* The ML code raises Parse_error */
              sp--;
            }
          }
        } else {
          if (env[env_curr_char] === 0)
            return RAISE_PARSE_ERROR; /* The ML code raises Parse_error */
          if (caml_parser_trace) log("Discarding last token read");
          env[env_curr_char] = -1;
          cmd = loop;
          continue the_loop;
        }
      // Unreachable
      case 8: //shift:
        // biome-ignore lint/suspicious/noFallthroughSwitchClause:
        env[env_curr_char] = -1;
        if (errflag > 0) errflag--;
      // fallthrough
      case 9: //shift_recover:
        // biome-ignore lint/suspicious/noFallthroughSwitchClause:
        if (caml_parser_trace)
          log("State " + state + ": shift to state " + tables.table[n2]);
        state = tables.table[n2];
        sp++;
        if (sp >= env[env_stacksize]) {
          res = GROW_STACKS_1;
          break the_loop;
        }
      // fallthrough
      /* The ML code resizes the stacks */
      case 2: //STACKS_GROWN_1:
        env[env_s_stack][sp + 1] = state;
        env[env_v_stack][sp + 1] = env[env_lval];
        env[env_symb_start_stack][sp + 1] = env[env_symb_start];
        env[env_symb_end_stack][sp + 1] = env[env_symb_end];
        cmd = loop;
        continue the_loop;

      case 10: //reduce:
        // biome-ignore lint/suspicious/noFallthroughSwitchClause:
        if (caml_parser_trace) log("State " + state + ": reduce by rule " + n);
        var m = tables.len[n];
        env[env_asp] = sp;
        env[env_rule_number] = n;
        env[env_rule_len] = m;
        sp = sp - m + 1;
        m = tables.lhs[n];
        state1 = env[env_s_stack][sp];
        n1 = tables.gindex[m];
        n2 = n1 + state1;
        if (
          n1 !== 0 &&
          n2 >= 0 &&
          n2 <= tables[tbl_tablesize] &&
          tables.check[n2] === state1
        )
          state = tables.table[n2];
        else state = tables.dgoto[m];
        if (sp >= env[env_stacksize]) {
          res = GROW_STACKS_2;
          break the_loop;
        }
      // fallthrough
      /* The ML code resizes the stacks */
      case 3: //STACKS_GROWN_2:
        res = COMPUTE_SEMANTIC_ACTION;
        break the_loop;
      /* The ML code calls the semantic action */
      case 4: //SEMANTIC_ACTION_COMPUTED:
        env[env_s_stack][sp + 1] = state;
        env[env_v_stack][sp + 1] = arg;
        var asp = env[env_asp];
        env[env_symb_end_stack][sp + 1] = env[env_symb_end_stack][asp + 1];
        if (sp > asp) {
          /* This is an epsilon production. Take symb_start equal to symb_end. */
          env[env_symb_start_stack][sp + 1] = env[env_symb_end_stack][asp + 1];
        }
        cmd = loop;
        continue the_loop;
      /* Should not happen */
      default:
        return RAISE_PARSE_ERROR;
    }
  }
  // SAVE
  env[env_sp] = sp;
  env[env_state] = state;
  env[env_errflag] = errflag;
  return res;
}

//Provides: caml_set_parser_trace
//Requires: caml_parser_trace
function caml_set_parser_trace(bool) {
  var oldflag = caml_parser_trace;
  caml_parser_trace = bool;
  return oldflag;
}
